//
//  ACAssetAccessManager.m
//  AlbumFetch
//
//  Created by 黄志明 on 2017/2/6.
//  Copyright © 2017年 黄志明. All rights reserved.
//

#import "ACAssetAccessManager.h"
#import "ACAssetModel.h"
#import <AssetsLibrary/AssetsLibrary.h>

@interface ACAssetAccessManager()

@property (nonatomic, strong) ALAssetsLibrary *assetLibrary;
@property (nonatomic, assign) CGSize defaultPhotoSize;

@property (nonatomic, strong) dispatch_semaphore_t fetchAssetSemaphore;

@end

@implementation ACAssetAccessManager

+ (instancetype)sharedManager
{
    static ACAssetAccessManager *assetAccessManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        assetAccessManager = [[self alloc] init];
    });
    
    return assetAccessManager;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        _defaultPhotoSize = [UIScreen mainScreen].bounds.size;
    }
    
    return self;
}

/// Return YES if Authorized 返回YES如果得到了授权
- (BOOL)authorizationStatusAuthorized
{
    return YES;
}

// 照片库的授权状态
- (ACAuthorizationStatus)authorizationStatus
{
    if ([self isIOS8OrLater])
    {
        return (ACAuthorizationStatus)[PHPhotoLibrary authorizationStatus];
    }
    else
    {
        return (ACAuthorizationStatus)[ALAssetsLibrary authorizationStatus];
    }
}

// 获取所有只包含照片相册信息
- (void)fetchAllPhotoAlbum:(void(^)(NSArray <ACAlbumModel *> *photoAlbum))completionBlock
{
    [self fetchAssetAlbum:ACAssetMediaTypePhoto completion:completionBlock];
}

// 获取所有只含视频的相册信息
- (void)fetchAllVideoAlbum:(void(^)(NSArray <ACAlbumModel *> *photoAlbum))completionBlock
{
    [self fetchAssetAlbum:ACAssetMediaTypeVideo completion:completionBlock];
}

// 获取所有只含音频的相册信息
- (void)fetchAllAudioAlbum:(void(^)(NSArray <ACAlbumModel *> *photoAlbum))completionBlock
{
    [self fetchAssetAlbum:ACAssetMediaTypeAudio completion:completionBlock];
}

// 获取含有指定类型文件的相册信息
- (void)fetchAssetAlbum:(ACAssetMediaType)mediaType completion:(void(^)(NSArray <ACAlbumModel *> *photoAlbum))completionBlock
{
    NSMutableArray *array = [NSMutableArray array];
    
    if ([self isIOS8OrLater])
    {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
            PHFetchOptions *option = [[PHFetchOptions alloc] init];
            
            NSString *predicateString = @"";
            if (mediaType & ACAssetMediaTypePhoto)
            {
                predicateString = [NSString stringWithFormat:@"mediaType == %ld", PHAssetMediaTypeImage];
            }
            
            if (mediaType & ACAssetMediaTypeVideo)
            {
                if (predicateString.length > 0)
                {
                    predicateString = [predicateString stringByAppendingFormat:@" || mediaType == %ld", PHAssetMediaTypeVideo];
                }
                else
                {
                    predicateString = [NSString stringWithFormat:@"mediaType == %ld", PHAssetMediaTypeVideo];
                }
            }
            
            if (mediaType & ACAssetMediaTypeAudio)
            {
                if (predicateString.length > 0)
                {
                    predicateString = [predicateString stringByAppendingFormat:@" || mediaType == %ld", PHAssetMediaTypeAudio];
                }
                else
                {
                    predicateString = [NSString stringWithFormat:@"mediaType == %ld", PHAssetMediaTypeAudio];
                }
            }
            
            option.predicate = [NSPredicate predicateWithFormat:predicateString];
            option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
            PHFetchResult <PHAssetCollection *>*smartAlbumResult = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum
                                                                                                            subtype:PHAssetCollectionSubtypeAny
                                                                                                            options:nil];
            [smartAlbumResult enumerateObjectsUsingBlock:^(PHAssetCollection * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                
                PHFetchResult *fetchResult = [PHAsset fetchAssetsInAssetCollection:obj options:option];
                if (fetchResult.count < 1) return;
                if ([obj.localizedTitle containsString:@"Deleted"] ||
                    [obj.localizedTitle isEqualToString:@"最近删除"] ||
                    [obj.localizedTitle isEqualToString:@"Recently Added"] ||
                    [obj.localizedTitle isEqualToString:@"最近添加"]) return;
                
                if ([obj.localizedTitle isEqualToString:@"Camera Roll"] ||
                    [obj.localizedTitle isEqualToString:@"相机胶卷"])
                {
                    [array insertObject:[self assetAlbumModelWithResult:fetchResult name:obj.localizedTitle albumId:[obj localIdentifier] filterAssetType:mediaType] atIndex:0];
                }
                else
                {
                    [array addObject:[self assetAlbumModelWithResult:fetchResult name:obj.localizedTitle albumId:[obj localIdentifier] filterAssetType:mediaType]];
                }
                
            }];
            
            dispatch_async(dispatch_get_main_queue(), ^{
                completionBlock(array);
            });
            
        });
    }
    else
    {
        [self.assetLibrary enumerateGroupsWithTypes:ALAssetsGroupAll
                                         usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
                                             
                                             
                                             
                                         }
                                       failureBlock:^(NSError *error) {
                                           
                                           dispatch_async(dispatch_get_main_queue(), ^{
                                               completionBlock(nil);
                                           });
                                           
                                       }];
    }
}

// 获取所有相册内的所有asset
- (void)fetchAllAssetsFromFetchResult:(ACAlbumModel *)albumModel assetType:(ACAssetMediaType)mediaType completion:(void(^)(NSArray <ACAssetModel *> *photos))completionBlock
{
    if (!completionBlock)
    {
        return;
    }
    
    NSMutableArray *assetsArray = [NSMutableArray array];
    id result = albumModel.result;
    if ([result isKindOfClass:[PHFetchResult class]])
    {
        PHFetchResult *fetchResult = (PHFetchResult *)result;
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
           
            [fetchResult enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                
                PHAsset *phAsset = (PHAsset *)obj;
                PHAssetMediaType phAssetMediaType = phAsset.mediaType;
                
                ACAssetModel *assetModel = nil;
                if ((mediaType & ACAssetMediaTypePhoto) && phAssetMediaType == PHAssetMediaTypeImage)
                {
                    assetModel = [ACAssetModel modelWithAsset:phAsset inAlbum:albumModel.albumIdentifier type:ACAssetModelTypePhoto];
                }
                else if ((mediaType & ACAssetMediaTypeVideo) && phAssetMediaType == PHAssetMediaTypeVideo)
                {
                    assetModel = [ACAssetModel modelWithAsset:phAsset inAlbum:albumModel.albumIdentifier type:ACAssetModelTypeVideo];
                }
                else if ((mediaType & ACAssetMediaTypeAudio) && phAssetMediaType == PHAssetMediaTypeAudio)
                {
                    assetModel = [ACAssetModel modelWithAsset:phAsset inAlbum:albumModel.albumIdentifier type:ACAssetModelTypeAudio];
                }
                
                if (assetModel)
                {
                    [assetsArray addObject:assetModel];
                }
                
            }];
            
            /////
            dispatch_async(dispatch_get_main_queue(), ^{
               
                completionBlock(assetsArray);
                
            });
            
        });
    }
    else if ([result isKindOfClass:[ALAssetsGroup class]])
    {
        
#warning 这里iOS7下好像没有音频获取的enum
        ALAssetsGroup *assetsGroup = (ALAssetsGroup *)result;
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
            [assetsGroup enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *resultAsset, NSUInteger index, BOOL *stop) {
                
                if (!result)
                {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        completionBlock(assetsArray);
                    });
                }
                
                NSString *assetContentType = [resultAsset valueForProperty:ALAssetPropertyType];
                ACAssetModel *assetModel = nil;
                if ((mediaType & ACAssetMediaTypePhoto) && [assetContentType isEqualToString:ALAssetTypePhoto])
                {
                    assetModel = [ACAssetModel modelWithAsset:resultAsset inAlbum:albumModel.albumIdentifier type:ACAssetModelTypePhoto];
                }
                else if ((mediaType & ACAssetMediaTypeVideo) && [assetContentType isEqualToString:ALAssetTypeVideo])
                {
                    assetModel = [ACAssetModel modelWithAsset:resultAsset inAlbum:albumModel.albumIdentifier type:ACAssetModelTypeVideo];
                }
                
                if (assetModel)
                {
                    [assetsArray addObject:assetModel];
                }
                
            }];
            
            /////
            dispatch_async(dispatch_get_main_queue(), ^{
                
                completionBlock(assetsArray);
                
            });
            
        });
    }
    else if ([result isKindOfClass:[NSArray class]])
    {
        /// 这里异步还需要处理
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
           
            for (ACAlbumModel *albumModel in result)
            {
                [self fetchAllAssetsFromFetchResult:albumModel assetType:mediaType completion:^(NSArray<ACAssetModel *> *photos) {
                   
                    [assetsArray addObjectsFromArray:photos];
                    
                    dispatch_semaphore_signal(self.fetchAssetSemaphore);
                    
                }];
                
                dispatch_semaphore_wait(self.fetchAssetSemaphore, DISPATCH_TIME_FOREVER);
            }
        });
    }
    else
    {
        completionBlock(assetsArray);
    }
}

// 获取相册封面照片
- (PHImageRequestID)postImageWithAlbum:(ACAlbumModel *)albumModel size:(CGSize)imageSize completion:(void(^)(UIImage *posterImage))completionBlock
{
    if ([self isIOS8OrLater])
    {
        PHAsset *phAsset = nil;
        if ([albumModel.result isKindOfClass:[NSArray class]])
        {
            phAsset = [((ACAlbumModel *)[albumModel.result firstObject]).result firstObject];
        }
        else
        {
            phAsset = [albumModel.result lastObject];
        }
        
        PHImageRequestID imageRequestID = [self fetchImageInAsset:phAsset size:imageSize completion:^(UIImage *photo, NSDictionary *info, BOOL isDegraded) {
            
            if (completionBlock) {
                completionBlock(photo);
            }
            
        }];
        
        return imageRequestID;
    }
    else
    {
        id group = albumModel.result;
        ALAssetsGroup *assetsGroup = nil;
        if ([group isKindOfClass:[ALAssetsGroup class]])
        {
            assetsGroup = (ALAssetsGroup *)group;
        }
        else if ([group isKindOfClass:[NSArray class]])
        {
            NSArray <ACAlbumModel *> *models = (NSArray *)group;
            if (models.count > 0)
            {
                assetsGroup = models[0].result;
            }
        }
        
        UIImage *postImage = [UIImage imageWithCGImage:assetsGroup.posterImage];
        if (completionBlock) completionBlock(postImage);
    }
    
    return 0;
}

// 获取相册图片，传size会返回以size为大小的图片  ios8 以后返回的PHImageRequestID 可用于取消获取的请求
- (PHImageRequestID)fetchImageInAsset:(id)asset size:(CGSize)size completion:(void (^)(UIImage *photo,NSDictionary *info, BOOL isDegraded))completion
{
    if ([asset isKindOfClass:[PHAsset class]])
    {
        PHAsset *phAsset = (PHAsset *)asset;
        CGSize imageSize;
        CGFloat aspectRatio = phAsset.pixelWidth / (CGFloat)phAsset.pixelHeight;
        CGFloat pixelWidth = ceil(size.width * [UIScreen mainScreen].scale);
        CGFloat pixelHeight = ceil(pixelWidth / aspectRatio);
        
        imageSize = CGSizeMake(pixelWidth, pixelHeight);
        
        // ipad下如果宽度太小，图片可能拿不到，这里固定ipad情况下，取的大小为180-200px
        NSString* strDevice = [[UIDevice currentDevice].model substringToIndex:4];
        if ([strDevice isEqualToString:@"iPad"] && pixelWidth < 380)
        {
            imageSize = CGSizeMake(380, 380);
        }
        
        PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
        options.synchronous = NO;
        options.resizeMode = PHImageRequestOptionsResizeModeFast;
        options.deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic;
        PHImageRequestID imageRequestID = [[PHImageManager defaultManager] requestImageForAsset:phAsset
                                                                                     targetSize:imageSize
                                                                                    contentMode:PHImageContentModeAspectFill
                                                                                        options:options
                                                                                  resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
                                                                                      
//                                                                                      判断图片是否下载完毕
//                                                                                      BOOL isDownloadFinished = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
                                                                                      
                                                                                      if (/*isDownloadFinished && */result)
                                                                                      {
                                                                                          if (completion)
                                                                                          {
                                                                                              dispatch_async(dispatch_get_main_queue(), ^{
                                                                                                  
                                                                                                  completion(result, @{@"ImageIdentifier":phAsset.localIdentifier}, [[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
                                                                                                  
                                                                                              });
                                                                                          }
                                                                                      }
                                                                                      
                                                                                      // iCloud 上的照片暂时不做处理
                                                                                      /*
                                                                                       if ([info objectForKey:PHImageResultIsInCloudKey] && !result)
                                                                                       {
                                                                                       PHImageRequestOptions *option = [[PHImageRequestOptions alloc]init];
                                                                                       option.networkAccessAllowed = YES;
                                                                                       option.synchronous = NO;
                                                                                       [[PHImageManager defaultManager] requestImageDataForAsset:asset options:option resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
                                                                                       UIImage *resultImage = [UIImage imageWithData:imageData scale:0.1];
                                                                                       resultImage = [self scaleImage:resultImage toSize:size];
                                                                                       if (resultImage && completion) {
                                                                                       completion(resultImage, info, [[info objectForKey:PHImageResultIsDegradedKey] boolValue]);
                                                                                       }
                                                                                       }];
                                                                                       }
                                                                                       */
                                                                                      
                                                                                      
                                                                                  }];
        
        return imageRequestID;
    }
    else if ([asset isKindOfClass:[ALAsset class]])
    {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
            ALAsset *alAsset = (ALAsset *)asset;
            CGImageRef thumbnailImageRef = alAsset.thumbnail;
            UIImage *thumbnailImage = [UIImage imageWithCGImage:thumbnailImageRef scale:2.0 orientation:UIImageOrientationUp];
            if (CGSizeEqualToSize(size, _defaultPhotoSize))
            {
                ALAssetRepresentation *representation = [alAsset defaultRepresentation];
                CGImageRef fullScreenImageRef = [representation fullScreenImage];
                thumbnailImage = [UIImage imageWithCGImage:fullScreenImageRef scale:2.0 orientation:UIImageOrientationUp];
            }
            
            dispatch_async(dispatch_get_main_queue(), ^{
                if (completion) {
                    completion(thumbnailImage, @{@"ImageIdentifier":[alAsset valueForProperty:@"ALAssetPropertyAssetURL"]}, NO);
                }
            });
            
        });
    }
    else
    {
        if (completion) {
            completion(nil, nil, NO);
        }
    }
    
    return 0;
}

// 获取相册大图-fullscreen图片
- (PHImageRequestID)fetchFullScreenImageInAsset:(id)asset completion:(void (^)(UIImage *photo,NSDictionary *info,BOOL isDegraded))completion
{
    return [self fetchImageInAsset:asset size:[UIScreen mainScreen].bounds.size completion:completion];
}

// 取消获取图片的请求 iOS8以后有效
- (void)cancelFetchReqeust:(PHImageRequestID)imageRequestID
{
    if ([self isIOS8OrLater])
    {
        [[PHImageManager defaultManager] cancelImageRequest:imageRequestID];
    }
}

// 根据类型，获取group（相册）实体
- (void)fetchAllAssetAlbum:(ACAssetMediaType)assetMediaType completion:(void (^)(NSArray <ACAlbumModel *> *photoAlbum))completionBlock
{
    [self fetchAssetAlbum:assetMediaType completion:^(NSArray<ACAlbumModel *> *assetAlbum) {
       
        if (completionBlock) {
            completionBlock(assetAlbum);
        }
        
    }];
}

// 根据类型，获取group（相册）内的所有asset(照片、视频、音频 实体)
- (void)fetchAllAssetsFromGroupResult:(ACAlbumModel *)albumModel assetMediaType:(ACAssetMediaType)assetMediaType completion:(void(^)(NSArray <ACAssetModel *> *photos))completionBlock
{
    [self fetchAllAssetsFromGroupResult:albumModel.result assetMediaType:assetMediaType completion:^(NSArray<ACAssetModel *> *albumPhotos) {
        
        if (completionBlock) {
            completionBlock(albumPhotos);
        }
        
    }];
}

// 根据Id获取Asset （ios8 以前 assetIdentifier 是ALAsset的 ALAssetPropertyAssetURL ios8以后是PHObject的localIdentifier）
- (void)fetchAssetWithIdentifier:(id)assetIdentifier withAlbumIdentifier:(NSString *)albumIdentifier complete:(void (^)(ACAssetModel *assetModel))completionBlock
{
    if (!assetIdentifier)
    {
        if (completionBlock) completionBlock(nil);
    
        return;
    }
    
    if ([self isIOS8OrLater])
    {
        PHAsset *phAsset = nil;
        if ([assetIdentifier isKindOfClass:[NSString class]])
        {
            phAsset = [PHAsset fetchAssetsWithLocalIdentifiers:@[assetIdentifier] options:nil].firstObject;
        }
        else if ([assetIdentifier isKindOfClass:[NSURL class]])
        {
            phAsset = [PHAsset fetchAssetsWithALAssetURLs:@[assetIdentifier] options:nil].firstObject;
        }
        
        if (phAsset)
        {
            ACAssetModel *model = [ACAssetModel modelWithAsset:phAsset inAlbum:albumIdentifier type:[self assetModelType:phAsset]];
            
            if (completionBlock)
            {
                completionBlock(model);
            }
        }
        else
        {
            if (completionBlock) {
                completionBlock(nil);
            }
        }
    }
    else
    {
        [self.assetLibrary assetForURL:assetIdentifier resultBlock:^(ALAsset *asset) {
            
            ACAssetModel *model = [ACAssetModel modelWithAsset:asset inAlbum:albumIdentifier type:[self assetModelType:asset]];
            if (completionBlock)
            {
                completionBlock(model);
            }
            
        } failureBlock:^(NSError *error) {
            
            if (completionBlock) {
                completionBlock(nil);
            }
            
        }];
    }
    
}

#pragma mark - Saving to system album

// 保存图片到相册
- (void)savePhotoToAlbum:(UIImage *)image completion:(void (^)(ACAssetModel *assetModel))completeion
{}

// 保存视频到相册
- (void)saveVideoToAlbum:(NSURL *)videoURL completion:(void (^)(ACAssetModel *assetModel))completion
{}

#pragma mark - Video 

// 获取从UIImagePickerController选中的原始或者经过裁剪视频信息
- (void)fetchAssetWithReferenceURL:(NSURL *)referenceURL mediaURL:(NSURL *)mediaURL complete:(void (^)(ACAssetModel *assetModel))completionBlock
{
    
}

#pragma mark -- Private method

- (BOOL)isIOS8OrLater
{
    return ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0);
}

- (NSInteger)assetCountInResult:(id)result filterAssetType:(ACAssetMediaType)filterType
{
    NSInteger count = 0;
    if ([result isKindOfClass:[PHFetchResult class]])
    {
        PHFetchResult *fetchResult = (PHFetchResult *)result;
        count = fetchResult.count;
    }
    else if ([result isKindOfClass:[ALAssetsGroup class]])
    {
        ALAssetsFilter *assetsFilter = [ALAssetsFilter allPhotos];
//        if (_assetType == ACAssetMediaTypeVideo)
//        {
//            assetsFilter = [ALAssetsFilter allVideos];
//        }
//        else if (_assetType == ACAssetMediaTypeAudio)
//        {
//            assetsFilter = [ALAssetsFilter allAssets];
//        }
        
        if (filterType & ACAssetMediaTypePhoto)
        {
            
        }
        
        
        
        ALAssetsGroup *assetsGroup = (ALAssetsGroup *)result;
        [assetsGroup setAssetsFilter:assetsFilter];
        count = [assetsGroup numberOfAssets];
    }
    else if ([result isKindOfClass:[NSArray class]])
    {
        for (id tmpResult in result)
        {
            if ([tmpResult isKindOfClass:[ACAlbumModel class]])
                count += [self assetCountInResult:((ACAlbumModel *)tmpResult).result filterAssetType:filterType];
        }
    }
    
    return count;
}

- (ACAlbumModel *)assetAlbumModelWithResult:(id)result name:(NSString *)name albumId:(NSString *)albumId filterAssetType:(ACAssetMediaType)filterType
{
    ACAlbumModel *albumModel = [[ACAlbumModel alloc] init];
    albumModel.name = name;
    albumModel.result = result;
    albumModel.count = [self assetCountInResult:result filterAssetType:filterType];
    albumModel.albumIdentifier = albumId;
    
    return albumModel;
}

- (ACAssetModelType)assetModelType:(id)asset
{
    if ([asset isKindOfClass:[PHAsset class]])
    {
        return (ACAssetModelType)((PHAsset *)asset).mediaType;
    }
    else if ([asset isKindOfClass:[ALAsset class]])
    {
        NSString *assetType = [asset valueForProperty:ALAssetPropertyType];
        if ([assetType isEqualToString:ALAssetTypePhoto])
        {
            return ACAssetModelTypePhoto;
        }
        else if ([assetType isEqualToString:ALAssetTypeVideo])
        {
            return ACAssetModelTypeVideo;
        }
    }
    
    return ACAssetModelTypeUnknown;
}

#pragma mark - Getter

- (ALAssetsLibrary *)assetLibrary {
    if (_assetLibrary == nil)
    {
        _assetLibrary = [[ALAssetsLibrary alloc] init];
    }
    
    return _assetLibrary;
}

- (dispatch_semaphore_t)fetchAssetSemaphore
{
    if (!_fetchAssetSemaphore)
    {
        _fetchAssetSemaphore = dispatch_semaphore_create(1);
    }
    
    return _fetchAssetSemaphore;
}

@end
